package workflow.component {
import flash.events.MouseEvent;
import flash.geom.Point;

import mx.collections.ArrayCollection;
import mx.core.DragSource;
import mx.core.UIComponent;
import mx.events.DragEvent;
import mx.managers.DragManager;

import spark.components.SkinnableContainer;

import workflow.constant.DragConst;
import workflow.element.CircleNode;
import workflow.element.ElementBase;
import workflow.element.RectangleNode;
import workflow.element.TriangleNode;
import workflow.event.AdjustElementEvent;
import workflow.event.SelectElementEvent;
import workflow.skin.DrawingBoardSkin;

public class DrawingBoard extends SkinnableContainer {

	private var _selectedElements:ArrayCollection = new ArrayCollection();

	private var _draggingElement:Boolean;

	/**
	 * mouse coordinate when drag start
	 */
	private var _dragStartPoint:Point;

	private var _adjustingElement:Boolean;

	public function DrawingBoard() {
		super();

		setStyle("skinClass", Class(DrawingBoardSkin));
		addEventHandler();
	}

	private function addEventHandler():void {
		addEventListener(DragEvent.DRAG_ENTER, dragEnterHandler);
		addEventListener(DragEvent.DRAG_DROP, dragDropHandler);
		addEventListener(SelectElementEvent.SELECT, selectElementHandler);
		addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
		addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
		addEventListener(AdjustElementEvent.BEGIN, beginAdjustElementHandler);
		addEventListener(AdjustElementEvent.END, endAdjustElementHandler);
	}

	private function createElement(type:String):ElementBase {
		var element:ElementBase;
		switch (type) {
		case DragConst.TYPE_NODE_CIRCLE:
			element = new CircleNode();
			break;
		case DragConst.TYPE_NODE_RECTANGLE:
			element = new RectangleNode();
			break;
		case DragConst.TYPE_NODE_TRIANGLE:
			element = new TriangleNode();
			break;
		}
		return element;
	}

	private function addElementIntoBoard(element:ElementBase):void {
		addElement(element);
	}

	//------------------------------------------------------------
	//
	// Event Handlers
	//
	//------------------------------------------------------------

	private function dragEnterHandler(e:DragEvent):void {
		var ds:DragSource = e.dragSource;
		if (ds.hasFormat(DragConst.ELEMENT_TYPE)) {
			var target:UIComponent = e.currentTarget as UIComponent;
			DragManager.acceptDragDrop(target);
			_draggingElement = true;
		}
	}

	private function dragDropHandler(e:DragEvent):void {
		var ds:DragSource = e.dragSource;
		var element:ElementBase;

		if (ds.hasFormat(DragConst.ELEMENT_TYPE)) {
			var type:String = ds.dataForFormat(DragConst.ELEMENT_TYPE) as String;
			element = createElement(type);
		} else {
			return;
		}

		var xoffset:Number = ds.dataForFormat(DragConst.XOFFSET) as Number;
		var yoffset:Number = ds.dataForFormat(DragConst.YOFFSET) as Number;

		// make mouse offset point relative to left top point of element is the same
		// when dragging and dropping
		element.x = mouseX - xoffset;
		element.y = mouseY - yoffset;

		addElementIntoBoard(element);
		_draggingElement = false;
	}

	private function selectElementHandler(e:SelectElementEvent):void {
		if (e.addElement) {
			if (_selectedElements.contains(e.element)) {
				_selectedElements.removeItemAt(_selectedElements.getItemIndex(e.element));
			} else {
				_selectedElements.addItem(e.element);
			}
		} else {
			// if click on selected element, do nothing
			// if click on unselected element, select the new element
			if (!_selectedElements.contains(e.element)) {
				_selectedElements.removeAll();
				_selectedElements.addItem(e.element);
			}
		}

		_dragStartPoint = e.dragStartPoint;
	}

	private function mouseDownHandler(e:MouseEvent):void {
		_selectedElements.removeAll();
	}

	private function mouseMoveHandler(e:MouseEvent):void {
		if (e.buttonDown && _selectedElements.length > 0 && !_draggingElement && !_adjustingElement) {
			moveElements(e);
			trace("board mouseMoveHandler" + e.currentTarget.toString());
		}
	}

	private function beginAdjustElementHandler(e:AdjustElementEvent):void {
		_adjustingElement = true;
	}

	private function endAdjustElementHandler(e:AdjustElementEvent):void {
		_adjustingElement = false;
	}

	private function moveElements(e:MouseEvent):void {
		var point:Point = new Point(e.stageX, e.stageY);
		var xOffset:Number = point.x - _dragStartPoint.x;
		var yOffset:Number = point.y - _dragStartPoint.y;

		for each (var element:ElementBase in _selectedElements) {
			element.x += xOffset;
			element.y += yOffset;
		}

		_dragStartPoint = point;
	}

}
}